﻿using Studio77.PopBall.Core;
using Studio77.PopBall.Entities;
using Studio77.PopBall.Pages;
using Studio77.PopBall.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Threading;

namespace Studio77.PopBall.Views
{
    public class GameCanvas : Canvas
    {
        int[,] datas = new int[GameStatics.RowCount, GameStatics.ColumnCount];
        GameItem[,] gameItems = new GameItem[GameStatics.RowCount, GameStatics.ColumnCount];
        List<int> selectKey = new List<int>();
        Random r = new Random(DateTime.Now.Millisecond);
        bool isElimition = false;
        object isElimitionSyncObj = new object();
        ScoreView scoreView = new ScoreView();
        StageEndScoreView endScoreView = new StageEndScoreView();

        public GameCanvas()
        {
            this.MouseLeftButtonDown += GameCanvas_MouseLeftButtonDown;
        }

        void GameCanvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            lock (isElimitionSyncObj)
            {
                if (isElimition)
                {
                    return;
                }
            }

            Point p = e.GetPosition(this);
            int row = (int)p.Y / GameStatics.ItemHeight;
            int column = (int)p.X / GameStatics.ItemWidth;

            if (row >= 0 && row <= GameStatics.RowCount && column >= 0 && column <= GameStatics.ColumnCount && datas[row, column] > 0 && datas[row, column] != 100)
            {
                //道具功能
                if (GamePage.Instance.isToolShow)
                {
                    if (GamePage.Instance.CurrentSelectToolType != 0)
                    {
                        if (StageManager.Instance.MagicBallCount > 0)
                        {
                            //使用道具
                            datas[row, column] = GamePage.Instance.CurrentSelectToolType;

                            gameItems[row, column].ChangeType(datas[row, column]);
                            SoundManager.PlayEffect(SoundManager.magicball);
                            StageManager.Instance.MagicBallCount--;

                            //清空之前的选中
                            foreach (var key in selectKey)
                            {
                                int sRow = key / GameStatics.ColumnCount;
                                int sColumn = key % GameStatics.ColumnCount;
                                gameItems[sRow, sColumn].SetUnSelected();
                            }
                            selectKey.Clear();
                        }

                        //隐藏界面
                        GamePage.Instance.HideToolArea();
                    }
                    else
                    {
                        //隐藏道具界面
                        GamePage.Instance.HideToolArea();
                    }
                    return;
                }

                if (!gameItems[row, column].IsSelected)
                {
                    List<int> tempSelectItems = new List<int>();
                    tempSelectItems.Add(row * GameStatics.ColumnCount + column);
                    //找到所有相关的色块，并全部选中，需要递归调用
                    FindRelationGameItem(datas[row, column], row, column, FindType.All, tempSelectItems);

                    if (tempSelectItems.Count > 1)
                    {
                        GamePage.Instance.ShowScoreTip(tempSelectItems.Count);

                        //清空之前的选中
                        foreach (var key in selectKey)
                        {
                            int sRow = key / GameStatics.ColumnCount;
                            int sColumn = key % GameStatics.ColumnCount;
                            gameItems[sRow, sColumn].SetUnSelected();
                        }
                        selectKey.Clear();

                        //有两个以上的选中了
                        //设置为选中状态
                        foreach (var key in tempSelectItems)
                        {
                            int sRow = key / GameStatics.ColumnCount;
                            int sColumn = key % GameStatics.ColumnCount;
                            gameItems[sRow, sColumn].SetSelected();
                            selectKey.Add(key);
                        }
                        SoundManager.PlayEffect(SoundManager.tap);
                    }
                }
                else
                {
                    //消除
                    if (selectKey.Count > 1)
                    {
                        lock (isElimitionSyncObj)
                        {
                            isElimition = true;
                        }
                        ProcessEliminate();
                    }
                }
            }

        }

        private void ProcessEliminate()
        {
            int unitDelay = 100;
            int count = 0;
            int delay = 300;
            List<int> includeColumns = new List<int>(5);
            //对清除列表进行排序
            //selectKey.Sort();
            foreach (var key in selectKey)
            {
                int sRow = key / GameStatics.ColumnCount;
                int sColumn = key % GameStatics.ColumnCount;
                gameItems[sRow, sColumn].Eliminate(count * unitDelay, count);
                datas[sRow, sColumn] = 0;
                count++;

                if (!includeColumns.Contains(sColumn))
                {
                    includeColumns.Add(sColumn);
                }

                //找到上面的球，进行弹跳动作
                if (sRow >= 1)
                {
                    for (int i = sRow - 1; i >= 0; i--)
                    {
                        if (datas[i, sColumn] > 0 && datas[i, sColumn] != 100)
                        {
                            gameItems[i, sColumn].Bounce();
                        }
                    }
                }
            }

            //显示得分情况
            int scoreDelay = count * unitDelay;
            DispatcherTimer scoreTimer = new DispatcherTimer();
            scoreTimer.Interval = TimeSpan.FromMilliseconds(scoreDelay);
            scoreTimer.Tick += (object sender, EventArgs e) =>
            {
                int score = ScoreHelper.GetScore(selectKey.Count);

                //显示得分
                scoreTimer.Stop();
                scoreView.Show(score, ScoreHelper.GetCommentType(selectKey.Count));

                //调用GamePage方法，增加总分数
                GamePage.Instance.AddScore(score);
            };
            scoreTimer.Start();

            delay += (count - 2) * unitDelay;
            DispatcherTimer moveTimer = new DispatcherTimer();
            moveTimer.Interval = TimeSpan.FromMilliseconds(delay);
            moveTimer.Tick += (object sender, EventArgs e) =>
            {
                moveTimer.Stop();

                double maxDelay = double.MinValue;
                foreach (var column in includeColumns)
                {
                    double movedelay = MoveBottom(column);
                    if (movedelay > maxDelay)
                    {
                        maxDelay = movedelay;
                    }
                }

                DispatcherTimer endEliminateTimer = new DispatcherTimer();
                endEliminateTimer.Interval = TimeSpan.FromMilliseconds(maxDelay);
                endEliminateTimer.Tick += (object ss, EventArgs ee) =>
                {
                    endEliminateTimer.Stop();
                    EndEliminateProcess();
                };
                endEliminateTimer.Start();

            };
            moveTimer.Start();
        }

        /// <summary>
        /// 处理消除成功
        /// </summary>
        private void EndEliminateProcess()
        {
            //尝试向左收缩
            MoveLeft();
            lock (isElimitionSyncObj)
            {
                isElimition = false;
            }
            selectKey.Clear();

            //判断是否还有可以消除的小球
            if (!CanEliminationBall())
            {
                //开始进行本关卡的结束动作
                DispatcherTimer blinkEliminateTimer = new DispatcherTimer();
                blinkEliminateTimer.Interval = TimeSpan.FromMilliseconds(500);
                blinkEliminateTimer.Tick += (object ss, EventArgs ee) =>
                {
                    SoundManager.PlayEffect(SoundManager.finish);
                    blinkEliminateTimer.Stop();
                    for (int i = 0; i < GameStatics.RowCount; i++)
                    {
                        for (int j = 0; j < GameStatics.ColumnCount; j++)
                        {
                            if (datas[i, j] > 0 && datas[i, j] != 100)
                            {
                                gameItems[i, j].Blink();
                            }
                        }
                    }

                };
                blinkEliminateTimer.Start();

                DispatcherTimer noEliminateTimer = new DispatcherTimer();
                noEliminateTimer.Interval = TimeSpan.FromMilliseconds(1500);
                noEliminateTimer.Tick += (object ss, EventArgs ee) =>
                {
                    noEliminateTimer.Stop();
                    ProcessNoEliminate();
                };
                noEliminateTimer.Start();
            }
        }

        /// <summary>
        /// 处理没有可消除的小球
        /// </summary>
        private void ProcessNoEliminate()
        {
            //通过奖励分的计算我们发现一个规律，2000,1980,1920,1820,1680,1500,1280,1020,720,380,0
            //他们的差是一个等差数列，20,60,100,140,180,220,260,300,340,380.
            List<int> lastItem = new List<int>();
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    if (datas[i, j] > 0 && datas[i, j] != 100)
                    {
                        lastItem.Add(i * GameStatics.ColumnCount + j);
                    }
                }
            }

            int bonus = 2000;
            int subBase = 20;
            int subUnit = 40;
            int delayUnit = 200;

            //先显示2000的加分
            this.endScoreView.Show();
            this.endScoreView.SetBonus(bonus, lastItem.Count);
            bool isEndSoundPlayed = false;

            for (int i = 0; i < lastItem.Count; i++)
            {
                int sRow = lastItem[i] / GameStatics.ColumnCount;
                int sColumn = lastItem[i] % GameStatics.ColumnCount;

                if (bonus > 0)
                {
                    bonus -= subBase;
                    subBase += subUnit;

                    gameItems[sRow, sColumn].Eliminate(delayUnit * (i + 1), 0);
                    MyDispatcherTimer tempTimer = new MyDispatcherTimer();
                    tempTimer.Parm = bonus;
                    tempTimer.Interval = TimeSpan.FromMilliseconds(delayUnit * (i + 1));
                    tempTimer.Tick += (object ss, EventArgs ee) =>
                    {
                        tempTimer.Stop();
                        endScoreView.SetBonus((int)tempTimer.Parm, lastItem.Count);
                    };
                    tempTimer.Start();

                }
                else
                {
                    if (!isEndSoundPlayed)
                    {
                        isEndSoundPlayed = true;
                        MyDispatcherTimer soundTimer = new MyDispatcherTimer();
                        soundTimer.Interval = TimeSpan.FromMilliseconds(delayUnit * 12);
                        soundTimer.Tick += (object ss, EventArgs ee) =>
                        {
                            soundTimer.Stop();
                            SoundManager.PlayEffect(SoundManager.exp);
                        };
                        soundTimer.Start();
                    }

                    gameItems[sRow, sColumn].Eliminate(delayUnit * 12, 0, false);
                    MyDispatcherTimer tempTimer = new MyDispatcherTimer();
                    tempTimer.Interval = TimeSpan.FromMilliseconds(delayUnit * 15);
                    tempTimer.Tick += (object ss, EventArgs ee) =>
                    {
                        tempTimer.Stop();
                        endScoreView.Hide();
                    };
                    tempTimer.Start();
                }
            }
            if (lastItem.Count <= 10 && bonus > 0)
            {
                MyDispatcherTimer tempTimer = new MyDispatcherTimer();
                tempTimer.Parm = bonus;
                tempTimer.Interval = TimeSpan.FromMilliseconds(delayUnit * (lastItem.Count + 2));
                tempTimer.Tick += (object ss, EventArgs ee) =>
                {
                    tempTimer.Stop();
                    endScoreView.Hide();
                    GamePage.Instance.AddScore(bonus);

                    MyDispatcherTimer notifyPageTimer = new MyDispatcherTimer();
                    notifyPageTimer.Interval = TimeSpan.FromMilliseconds(500);
                    notifyPageTimer.Tick += (object ss2, EventArgs ee2) =>
                    {
                        notifyPageTimer.Stop();
                        GamePage.Instance.NoEliminate();
                    };
                    notifyPageTimer.Start();
                };
                tempTimer.Start();
            }
            else
            {
                MyDispatcherTimer tempTimer = new MyDispatcherTimer();
                tempTimer.Interval = TimeSpan.FromMilliseconds(delayUnit * 12);
                tempTimer.Tick += (object ss, EventArgs ee) =>
                {
                    tempTimer.Stop();
                    endScoreView.Hide();
                    MyDispatcherTimer notifyPageTimer = new MyDispatcherTimer();
                    notifyPageTimer.Interval = TimeSpan.FromMilliseconds(500);
                    notifyPageTimer.Tick += (object ss2, EventArgs ee2) =>
                    {
                        notifyPageTimer.Stop();
                        GamePage.Instance.NoEliminate();
                    };
                    notifyPageTimer.Start();
                };
                tempTimer.Start();
            }
        }

        /// <summary>
        /// 判断是否还有可以消除的小球
        /// </summary>
        /// <returns></returns>
        private bool CanEliminationBall()
        {
            bool isfind = false;
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    if (datas[i, j] > 0 && datas[i, j] != 100)
                    {
                        List<int> find = new List<int>();
                        FindRelationGameItem(datas[i, j], i, j, FindType.All, find);
                        if (find.Count > 0)
                        {
                            isfind = true;
                            break;
                        }
                    }
                }
            }
            return isfind;
        }

        private void MoveLeft()
        {
            bool isProcessed = false;
            //判断一列是否为空
            for (int column = 0; column < GameStatics.ColumnCount; column++)
            {
                bool isEmpty = true;
                for (int row = 0; row < GameStatics.RowCount; row++)
                {
                    if (datas[row, column] > 0)
                    {
                        isEmpty = false;
                        break;
                    }
                }
                if (isEmpty)
                {
                    isProcessed = true;
                    //需要收缩 i-列 j-行
                    for (int i = column; i < GameStatics.ColumnCount; i++)
                    {
                        for (int j = 0; j < GameStatics.RowCount; j++)
                        {
                            if (i + 1 < GameStatics.ColumnCount)
                            {
                                datas[j, i] = datas[j, i + 1];
                            }
                            else
                            {
                                datas[j, i] = 100;
                            }
                        }

                    }
                    //防止出现多列为空的情况
                    column--;
                }
            }

            if (isProcessed)
            {
                //刷新界面
                RefreshGameItems();
            }

        }


        /// <summary>
        /// 向下移动
        /// </summary>
        /// <param name="column"></param>
        /// <returns></returns>
        private double MoveBottom(int column)
        {
            double result = 0;
            List<ItemChangeInfo> needToExchange = new List<ItemChangeInfo>();

            // 找到一个空的，往后寻找，找到替换，没找到break
            for (int i = GameStatics.RowCount - 1; i >= 0; i--)
            {
                int data = datas[i, column];
                if (data == 0)
                {
                    ItemChangeInfo findInfo = new ItemChangeInfo();
                    findInfo.StartX = -1;
                    findInfo.StartY = -1;
                    findInfo.EndX = -1;
                    findInfo.EndY = -1;

                    for (int ii = i - 1; ii >= 0; ii--)
                    {
                        int tempData = datas[ii, column];
                        if (tempData > 0)
                        {
                            findInfo.EndX = i;
                            findInfo.EndY = column;
                            findInfo.StartX = ii;
                            findInfo.StartY = column;
                            break;
                        }
                    }
                    if (findInfo.StartX != -1 && findInfo.EndX != -1)
                    {
                        //更新datas
                        int temp = datas[findInfo.StartX, findInfo.StartY];
                        datas[findInfo.StartX, findInfo.StartY] = datas[findInfo.EndX, findInfo.EndY];
                        datas[findInfo.EndX, findInfo.EndY] = temp;
                        needToExchange.Add(findInfo);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            // 互换并更新界面
            result = ExchangeItem(needToExchange);

            foreach (var findInfo in needToExchange)
            {
                //更新runes
                GameItem temp = gameItems[findInfo.StartX, findInfo.StartY];
                gameItems[findInfo.StartX, findInfo.StartY] = gameItems[findInfo.EndX, findInfo.EndY];
                gameItems[findInfo.EndX, findInfo.EndY] = temp;
            }

            return result;
        }

        /// <summary>
        /// 交换Ball
        /// </summary>
        /// <param name="needToExchange"></param>
        /// <param name="isOp"></param>
        /// <returns>返回动画结束的毫秒信息</returns>
        private double ExchangeItem(List<ItemChangeInfo> needToExchange)
        {
            double maxDuration = 0;
            foreach (var item in needToExchange)
            {
                //做动画改变位置
                GameItem rune = gameItems[item.StartX, item.StartY];
                //if (rune.IsRuneEnable)
                //{
                Storyboard storyBoard = new Storyboard();
                double durations = GetDuration(item);
                Duration duration = new Duration(TimeSpan.FromMilliseconds(durations));

                if (durations > maxDuration)
                {
                    maxDuration = durations;
                }

                DoubleAnimation daX = new DoubleAnimation();
                daX.Duration = duration;
                daX.To = item.EndX * GameStatics.ItemHeight;
                DoubleAnimation daY = new DoubleAnimation();
                daY.Duration = duration;
                daY.To = item.EndY * GameStatics.ItemWidth;

                //弹跳
                QuadraticEase bounce = new QuadraticEase();
                bounce.EasingMode = EasingMode.EaseIn;
                //bounce.Bounces = 2;
                //bounce.Bounciness = 5;
                daX.EasingFunction = bounce;
                daY.EasingFunction = bounce;

                Storyboard.SetTarget(storyBoard, rune);
                Storyboard.SetTargetProperty(daX, new PropertyPath(Canvas.TopProperty));
                Storyboard.SetTargetProperty(daY, new PropertyPath(Canvas.LeftProperty));
                storyBoard.Children.Add(daX);
                storyBoard.Children.Add(daY);

                storyBoard.Begin();
            }

            return maxDuration;
        }

        /// <summary>
        /// 递归寻找逻辑
        /// </summary>
        /// <param name="itemType"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="findType"></param>
        /// <param name="items"></param>
        private void FindRelationGameItem(int itemType, int row, int column, FindType findType, List<int> items)
        {
            if (findType != FindType.Bottom)
            {
                //向上找
                if (row - 1 >= 0)
                {
                    if (datas[row - 1, column] == itemType)
                    {
                        int itemKey = (row - 1) * GameStatics.ColumnCount + column;
                        if (!items.Contains(itemKey))
                        {
                            items.Add(itemKey);
                            //继续找
                            FindRelationGameItem(itemType, row - 1, column, FindType.Top, items);
                        }
                    }
                }
            }
            if (findType != FindType.Top)
            {
                //向下找
                if (row + 1 < GameStatics.RowCount)
                {
                    if (datas[row + 1, column] == itemType)
                    {
                        int itemKey = (row + 1) * GameStatics.ColumnCount + column;
                        if (!items.Contains(itemKey))
                        {
                            items.Add(itemKey);
                            //继续找
                            FindRelationGameItem(itemType, row + 1, column, FindType.Bottom, items);
                        }
                    }
                }
            }
            if (findType != FindType.Right)
            {
                //向左找
                if (column - 1 >= 0)
                {
                    if (datas[row, column - 1] == itemType)
                    {
                        int itemKey = row * GameStatics.ColumnCount + column - 1;
                        if (!items.Contains(itemKey))
                        {
                            items.Add(itemKey);
                            //继续找
                            FindRelationGameItem(itemType, row, column - 1, FindType.Left, items);
                        }
                    }
                }
            }

            if (findType != FindType.Left)
            {
                //向右找
                if (column + 1 < GameStatics.ColumnCount)
                {
                    if (datas[row, column + 1] == itemType)
                    {
                        int itemKey = row * GameStatics.ColumnCount + column + 1;
                        if (!items.Contains(itemKey))
                        {
                            items.Add(itemKey);
                            //继续找
                            FindRelationGameItem(itemType, row, column + 1, FindType.Right, items);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 继续进行游戏
        /// </summary>
        /// <param name="dictionary"></param>
        internal void ContinueGame(Dictionary<int, int> oldData)
        {
            selectKey.Clear();
            this.Children.Clear();
            isElimition = false;

            //初始化
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    datas[i, j] = oldData[i * GameStatics.ColumnCount + j];
                    GameItem item = new GameItem();
                    item.SetType(datas[i, j]);
                    Canvas.SetTop(item, i * GameStatics.ItemHeight);
                    Canvas.SetLeft(item, j * GameStatics.ItemWidth);
                    gameItems[i, j] = item;
                    this.Children.Add(item);
                }
            }
            AddOtherUI();

            EndEliminateProcess();
        }

        private void AddOtherUI()
        {

            if (!this.Children.Contains(scoreView))
            {
                this.Children.Add(scoreView);
                Canvas.SetLeft(scoreView, this.Width / 2 - 151);
                Canvas.SetTop(scoreView, this.Height / 2 - 85);
                Canvas.SetZIndex(scoreView, 100);
                scoreView.Hide();
            }
            if (!this.Children.Contains(endScoreView))
            {
                this.Children.Add(endScoreView);
                Canvas.SetTop(endScoreView, this.Height / 2 - 150);
                Canvas.SetZIndex(endScoreView, 101);
                endScoreView.Hide();
            }
        }

        /// <summary>
        /// 开始全新游戏
        /// </summary>
        internal void InitGame()
        {
            selectKey.Clear();
            this.Children.Clear();
            isElimition = false;

            //初始化
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    datas[i, j] = 0;
                    gameItems[i, j] = null;
                }
            }

            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    GameItem item = new GameItem();
                    int type = r.Next(5) + 1;
                    datas[i, j] = type;
                    item.SetType(type);
                    Canvas.SetTop(item, i * GameStatics.ItemHeight);
                    Canvas.SetLeft(item, j * GameStatics.ItemWidth);
                    gameItems[i, j] = item;
                    this.Children.Add(item);
                }
            }

            AddOtherUI();
            SoundManager.PlayEffect(SoundManager.stageStart);
        }

        public void RestartGame()
        {
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    int type = r.Next(5) + 1;
                    datas[i, j] = type;
                    GameItem item = gameItems[i, j];
                    Canvas.SetTop(item, i * GameStatics.ItemHeight);
                    Canvas.SetLeft(item, j * GameStatics.ItemWidth);
                    item.SetType(datas[i, j]);
                }
            }
            SoundManager.PlayEffect(SoundManager.stageStart);
            //EndEliminateProcess();
        }

        private void RefreshGameItems()
        {
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    GameItem item = gameItems[i, j];
                    Canvas.SetTop(item, i * GameStatics.ItemHeight);
                    Canvas.SetLeft(item, j * GameStatics.ItemWidth);
                    item.SetType(datas[i, j]);
                }
            }
        }

        public static double GetDuration(ItemChangeInfo item)
        {
            int baseValue = 57;
            double offset;
            int x = Math.Abs(item.StartX - item.EndX);
            int y = Math.Abs(item.StartY - item.EndY);
            if (x > 0 && y > 0)
            {
                offset = x * Math.Sqrt(2.0);
            }
            else
            {
                if (x > y)
                {
                    offset = x;
                }
                else
                {
                    offset = y;
                }
            }
            return baseValue * offset;
        }


        internal Dictionary<int, int> GetGameData()
        {
            Dictionary<int, int> result = new Dictionary<int, int>();
            for (int i = 0; i < GameStatics.RowCount; i++)
            {
                for (int j = 0; j < GameStatics.ColumnCount; j++)
                {
                    int key = i * GameStatics.ColumnCount + j;
                    result.Add(key, datas[i, j]);
                }
            }

            return result;
        }
    }
}
